package com.caits.lbs.framework.dao.impl;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.log4j.Logger;
import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.springframework.dao.DataAccessException;

import com.caits.lbs.bean.dbmodel.ETBase;
import com.caits.lbs.framework.Constants;
import com.caits.lbs.framework.log.CommonLogFactory;
import com.caits.lbs.framework.utils.JsonUtil;
import com.caits.lbs.framework.utils.StringUtils;
import com.caits.lbs.framework.utils.XmlUtil;
import com.common.ajax.server.IRequest;
import com.common.ajax.server.RequestParser;
import com.common.ajax.server.SessionMap;

/**
 * <p>
 * BaseXmlDaoService
 * </p>
 * <p>
 * 持久化业务xml服务处理入口类，所有提供xml服务的持久化类都继承此类 该类提供一组方法动态调用持久层IBusinessDao接口的实现
 * </p>
 * 
 * @author 周华彬(zhouhuabin@ctfo.com, zhou_hua_bin@163.com)
 * @version 0.0.0
 *          <table style="border:1px solid gray;">
 *          <tr>
 *          <th width="100px">版本号</th>
 *          <th width="100px">动作</th>
 *          <th width="100px">修改人</th>
 *          <th width="100px">修改时间</th>
 *          </tr>
 *          <!-- 以 Table 方式书写修改历史 -->
 *          <tr>
 *          <td>0.0.0</td>
 *          <td>创建类</td>
 *          <td>zhb</td>
 *          <td>2011-4-1 下午05:21:24</td>
 *          </tr>
 *          <tr>
 *          <td>0.0.0</td>
 *          <td>修改</td>
 *          <td>郭训常</td>
 *          <td>2011-04-20 下午13:02:30</td>
 *          </tr>
 *          </table>
 */
public abstract class BaseXmlDaoService implements IRequest {

	/** 日志记录器 */
	private Logger log = CommonLogFactory.getLog();

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.common.ajax.server.IRequest#request(java.lang.String,
	 * com.common.ajax.server.SessionMap)
	 */
	public String request(String xmlStr, SessionMap session)
			throws SecurityException, NoSuchMethodException,
			IllegalAccessException, InvocationTargetException, SQLException,
			RuntimeException {
		// request
		Document doc = XmlUtil.StringTodocument(xmlStr);
		Document resDoc = request(doc, session);
		return XmlUtil.documentToString(resDoc);
	}

	/**
	 * 公用方法(入口)
	 */
	@SuppressWarnings("unchecked")
	public Document request(Document doc, SessionMap session)
			throws SecurityException, NoSuchMethodException,
			IllegalArgumentException, IllegalAccessException,
			InvocationTargetException, RuntimeException {

		// request
		Element eRequest = doc.getRootElement();
		List<Element> lstRequestChild = eRequest.elements();
		Element data = (Element) lstRequestChild.get(0);
		String type = lstRequestChild.get(0).attributeValue(XML_TYPE);
		String server = eRequest.attributeValue(XML_SERVER);
		// response
		Element resResponse = DocumentHelper.createElement(XML_RESPONSE);
		Element resData = DocumentHelper.createElement(XML_DATA);
		resResponse.add(resData);
		resData.addAttribute(XML_TYPE, type);
		resData.addAttribute(IRequest.XML_RESULT, ""+ERROR_SUCCEED);
		resData.addAttribute(IRequest.XML_MSG, ERROR_SUCCEED_DESC);
		
		resResponse.addAttribute(XML_SERVER, server);
		Document resDoc = DocumentHelper.createDocument(resResponse);
		if(StringUtils.isNullOrBlank(server)){
			resDoc = RequestParser.createError(server,
					IRequest.ERROR_CLASS_NOT_FOUND, IRequest.ERROR_CLASS_NOT_FOUND_DESC);
			String resString = XmlUtil.documentToString(resDoc);
			log.error(IRequest.ERROR_CLASS_NOT_FOUND_DESC 	+ "\r\nerrXml:" + resString);
			return resDoc;
		}
		if(StringUtils.isNullOrBlank(type)){
			resDoc = RequestParser.createError(server,
					IRequest.ERROR_METHOD_NOT_FOUND, IRequest.ERROR_METHOD_NOT_FOUND_DESC);
			String resString = XmlUtil.documentToString(resDoc);
			log.error(IRequest.ERROR_METHOD_NOT_FOUND_DESC 	+ "\r\nerrXml:" + resString);
			return resDoc;
		}
		try {
			Object ret = null;
			if (validateSession(session, data, resData, type)) {
				Method method = this.getClass().getDeclaredMethod(type,
						Element.class, Element.class, SessionMap.class);
				ret = method.invoke(this, data, resData, session);
			}

			if (type.equals(Constants.SYS_OPERATOR_LOGIN)) {
				if (ret != null) {
					// session.setAttribute(Constants.SESSION_NAME, ret);
				}
			}

		} catch (IllegalArgumentException ex) {
			resDoc = RequestParser.createError(server,
					IRequest.ERROR_ILLEGAL_ACCESS, IRequest.ERROR_ILLEGAL_ACCESS_DESC+ex.getLocalizedMessage());
			String resString = XmlUtil.documentToString(resDoc);
			log.error(IRequest.ERROR_ILLEGAL_ACCESS_DESC + ex.getLocalizedMessage()
					+ "\r\nerrXml:" + resString, ex);

		} catch (DataAccessException de) {
			resDoc = RequestParser.createError(server,
					IRequest.ERROR_SQL_ACCESS, IRequest.ERROR_SQL_DESC+de.getLocalizedMessage());
			String resString = XmlUtil.documentToString(resDoc);
			log.error(IRequest.ERROR_SQL_DESC + de.getMessage()
					+ "\r\nerrXml:" + resString, de);
		} catch (InvocationTargetException ie) {
			resDoc = RequestParser.createError(server,
					IRequest.ERROR_INVOCATIONTARGET_ACCESS, IRequest.ERROR_INVOCATIONTARGET_DESC+StringUtils.null2default(ie.getLocalizedMessage(), ie.getTargetException().getLocalizedMessage()));
			String resString = XmlUtil.documentToString(resDoc);
			log.error(IRequest.ERROR_INVOCATIONTARGET_DESC + ie.getLocalizedMessage()
					+ "\r\nerrXml:" + resString, ie);
		}
		
		return resDoc;
	}

	/**
	 * 读取参数(单标签参数)
	 * 
	 * @param eRequest
	 *            请求xml
	 */
	@SuppressWarnings("unchecked")
	public Map<String, Object> getParamMap(Element eRequest) {
		List<Attribute> list = eRequest.attributes();
		Map<String, Object> paramMap = new HashMap<String, Object>();
		for (Attribute subInfoRoot : list) {
			paramMap.put(subInfoRoot.getName(), subInfoRoot.getValue());
		}

		String typename = eRequest.getParent().attributeValue("typename");
		String sessionid = eRequest.attributeValue("sessionid");
		paramMap.put("typename", typename);
		paramMap.put("sessionid", sessionid);
		return paramMap;
	}

	/**
	 * 调用DAO,根据参数作为属性，将列表bean转换为xml元素
	 * 
	 * @param daoObjcet
	 *            dao对象
	 * 
	 * @param paramMethod
	 *            dao方法名称数组
	 * 
	 * @param paramXML
	 *            输出Bean属性
	 * 
	 * @param eRequest
	 *            请求xml
	 * 
	 * @param resData
	 *            响应xml
	 */
	@SuppressWarnings("unchecked")
	public void callDAOToListXML(Object daoObjcet, String[] paramMethod,
			String[] paramXML, Element eRequest, Element resData)
			throws IllegalArgumentException, SecurityException,
			IllegalAccessException, InvocationTargetException,
			NoSuchMethodException, ClassNotFoundException {
		// call DAO
		Map<String, Object> paramMap = getParamMap(eRequest);
		Object page = paramMap.get("page");
		Object size = paramMap.get("size");
		Object topage = paramMap.get("topage");
		Class<? extends Object> daoClass = daoObjcet.getClass();
		List<ETBase> list;
		if ("".equals(page) || page == null || "".equals(size) || size == null) {// 不分页
			list = (List<ETBase>) daoClass.getDeclaredMethod(paramMethod[0],
					Map.class).invoke(daoObjcet, paramMap);

		} else {
			int ipage = Integer.parseInt(page.toString());// 当前页数
			int isize = Integer.parseInt(size.toString());// 每页记录数
			paramMap.put("startNum", isize * (ipage - 1));

			if (topage == null || "".equals(topage))
				paramMap.put("endNum", isize * ipage);
			else {
				int itopage = Integer.parseInt(topage.toString());// 当前页数
				paramMap.put("endNum", isize * itopage);
			}
			// 总记录数
			long total = (Long) daoClass.getDeclaredMethod(paramMethod[1],
					Map.class).invoke(daoObjcet, paramMap);

			long pages = total / isize;// 总页数
			if (total % isize != 0) {
				pages += 1;
			}
			resData.addAttribute("total", (new Long(total)).toString());
			resData.addAttribute("pages", (new Long(pages)).toString());

			list = (List<ETBase>) daoClass.getDeclaredMethod(paramMethod[0],
					Map.class).invoke(daoObjcet, paramMap);
		}
		// response XML
		if (list != null) {
			if (paramXML == null || paramXML.length == 0) {
				for (ETBase base : list) {
					resData.add(base.toElement());
				}
			} else {
				for (ETBase base : list) {
					resData.add(base.toElement(paramXML));
				}
			}
		}
	}

	/**
	 * 调用DAO,根据参数作为属性，将单个bean转换为单个元素
	 * 
	 * @param daoObjcet
	 *            dao对象
	 * 
	 * @param paramMethod
	 *            dao方法名称数组
	 * 
	 * @param paramXML
	 *            输出Bean属性
	 * 
	 * @param eRequest
	 *            请求xml
	 * 
	 * @param resData
	 *            响应xml
	 */
	public void callDAOToBeanXML(Object daoObjcet, String[] paramMethod,
			String[] paramXML, Element eRequest, Element resData)
			throws IllegalArgumentException, SecurityException,
			IllegalAccessException, InvocationTargetException,
			NoSuchMethodException, ClassNotFoundException {
		// call DAO
		Map<String, Object> paramMap = getParamMap(eRequest);
		Class<? extends Object> daoClass = daoObjcet.getClass();
		ETBase bean = (ETBase) daoClass.getDeclaredMethod(paramMethod[0],
				Map.class).invoke(daoObjcet, paramMap);
		// response XML
		if (bean != null) {
			if (paramXML == null || paramXML.length == 0) {
				resData.add(bean.toElement());
			} else {
				resData.add(bean.toElement(paramXML));
			}

		}

	}

	/**
	 * 调用DAO,根据参数作为属性，将单个Map转换为单个元素
	 * 
	 * @param daoObjcet
	 *            dao对象
	 * 
	 * @param paramMethod
	 *            dao方法名称数组
	 * 
	 * @param paramXML
	 *            输出Bean属性
	 * 
	 * @param eRequest
	 *            请求xml
	 * 
	 * @param resData
	 *            响应xml
	 */
	@SuppressWarnings("unchecked")
	public void callDAOToMapXML(Object daoObjcet, String[] paramMethod,
			String[] paramXML, Element eRequest, Element resData)
			throws IllegalArgumentException, SecurityException,
			IllegalAccessException, InvocationTargetException,
			NoSuchMethodException, ClassNotFoundException {
		// call DAO
		Map<String, Object> paramMap = getParamMap(eRequest);
		Class<? extends Object> daoClass = daoObjcet.getClass();
		Map<String, Object> resultMap = (Map<String, Object>) daoClass
				.getDeclaredMethod(paramMethod[0], Map.class).invoke(daoObjcet,
						paramMap);
		// response XML
		Element element = DocumentHelper.createElement(eRequest.getName());
		Set<String> keySet = resultMap.keySet();
		if (paramXML == null || paramXML.length == 0) {
			for (String key : keySet) {
				element.addAttribute(key.toLowerCase(),
						String.valueOf(resultMap.get(key)));
			}
		} else {
			for (String key : keySet) {
				if (StringUtils.findAttributes(key, paramXML)) {
					element.addAttribute(key.toLowerCase(),
							String.valueOf(resultMap.get(key)));
				}
			}
		}
		resData.add(element);
	}

	/**
	 * 调用DAO,根据多属性参数，将列表Map转换为xml列表
	 * 
	 * @param daoObjcet
	 *            dao对象
	 * 
	 * @param paramMethod
	 *            dao方法名称数组
	 * 
	 * @param paramXML
	 *            输出Bean属性
	 * 
	 * @param eRequest
	 *            请求xml
	 * 
	 * @param resData
	 *            响应xml
	 */
	@SuppressWarnings("unchecked")
	public void callDAOToListMapXML(Object daoObjcet, String[] paramMethod,
			String[] paramXML, Element eRequest, Element resData)
			throws IllegalArgumentException, SecurityException,
			IllegalAccessException, InvocationTargetException,
			NoSuchMethodException, ClassNotFoundException {
		// call DAO
		Map<String, Object> paramMap = getParamMap(eRequest);
		Object page = paramMap.get("page");
		Object size = paramMap.get("size");
		Object topage = paramMap.get("topage");
		Class<? extends Object> daoClass = daoObjcet.getClass();
		List<Map<String, Object>> paramKVList;
		if ("".equals(page) || page == null || "".equals(size) || size == null) {// 不分页
			paramKVList = (List<Map<String, Object>>) daoClass
					.getDeclaredMethod(paramMethod[0], Map.class).invoke(
							daoObjcet, paramMap);
		} else {
			int ipage = Integer.parseInt(page.toString());// 当前页数
			int isize = Integer.parseInt(size.toString());// 每页记录数
			paramMap.put("startNum", isize * (ipage - 1));
			if (topage == null || "".equals(topage))
				paramMap.put("endNum", isize * ipage);
			else {
				int itopage = Integer.parseInt(topage.toString());// 当前页数
				paramMap.put("endNum", isize * itopage);
			}

			// 总记录数
			long total = (Long) daoClass.getDeclaredMethod(paramMethod[1],
					Map.class).invoke(daoObjcet, paramMap);

			long pages = total / isize;// 总页数
			if (total % isize != 0) {
				pages += 1;
			}
			resData.addAttribute("total", (new Long(total)).toString());
			resData.addAttribute("pages", (new Long(pages)).toString());

			paramKVList = (List<Map<String, Object>>) daoClass
					.getDeclaredMethod(paramMethod[0], Map.class).invoke(
							daoObjcet, paramMap);
		}
		// response XML
		// Element element = new Element(eRequest.getName());
		Object o = null;
		if (paramXML == null || paramXML.length == 0) {
			for (Map<String, Object> tempMap : paramKVList) {
				Element element = DocumentHelper.createElement(eRequest
						.getName());
				Set<String> keySet = tempMap.keySet();
				for (String key : keySet) {
					o = tempMap.get(key);
					if (o == null) {
						element.addAttribute(key.toLowerCase(), "");
					} else {
						element.addAttribute(key.toLowerCase(),
								String.valueOf(o));
					}
				}
				resData.add(element);
			}

		} else {
			for (Map<String, Object> tempMap : paramKVList) {
				Element element = DocumentHelper.createElement(eRequest
						.getName());
				Set<String> keySet = tempMap.keySet();
				for (String key : keySet) {
					if (StringUtils.findAttributes(key, paramXML)) {
						o = tempMap.get(key);
						if (o == null) {
							element.addAttribute(key.toLowerCase(), "");
						} else {
							element.addAttribute(key.toLowerCase(),
									String.valueOf(o));
						}
					}
				}
				resData.add(element);
			}
		}

	}

	/**
	 * 处理调用DAO(单标签多属性参数，响应处理格式：List<Map<String, Object>>) 按照参数名称组织元素名称
	 * 
	 * @param daoObjcet
	 *            dao对象
	 * 
	 * @param paramMethod
	 *            dao方法名称数组
	 * 
	 * @param paramXML
	 *            输出Bean属性
	 * 
	 * @param eRequest
	 *            请求xml
	 * 
	 * @param resData
	 *            响应xml
	 */
	@SuppressWarnings("unchecked")
	public void callDAOToListElementNameMapXML(Object daoObjcet,
			String[] paramMethod, String[] paramXML, Element eRequest,
			Element resData) throws IllegalArgumentException,
			SecurityException, IllegalAccessException,
			InvocationTargetException, NoSuchMethodException,
			ClassNotFoundException {
		// call DAO
		Map<String, Object> paramMap = getParamMap(eRequest);
		Class<? extends Object> daoClass = daoObjcet.getClass();
		List<Map<String, Object>> paramKVList;

		paramKVList = (List<Map<String, Object>>) daoClass.getDeclaredMethod(
				paramMethod[0], Map.class).invoke(daoObjcet, paramMap);

		// response XML
		String tempParamXML = "";
		for (int i = 0; i < paramKVList.size(); i++) {
			if (paramXML.length <= i)
				tempParamXML = paramXML[paramXML.length - 1];
			else
				tempParamXML = paramXML[i];
			Element element = DocumentHelper.createElement(tempParamXML);
			Set<String> keySet = paramKVList.get(i).keySet();
			for (String key : keySet) {
				element.addAttribute(key.toLowerCase(),
						String.valueOf(paramKVList.get(i).get(key)));
			}
			resData.add(element);
		}

	}

	/**
	 * 登录判断
	 * 
	 * @param session
	 * @param resData
	 * @return
	 */
	public  boolean validateSession(SessionMap session, Element data,
			Element resData, String type) {
		boolean flag = true;// 标志,false不判断登陆
		Object sessionid = session.getAttribute(Constants.SESSION_NAME);
		if (flag && !type.equals(Constants.SYS_OPERATOR_LOGIN)) {

			if (sessionid == null) {
				Element base = DocumentHelper.createElement("ETBase");
				String msg = "用户未登录";
				base.addAttribute("result", "-1");
				base.addAttribute("msg", msg);
				resData.add(base);
				return false;
			} else {
				data.addAttribute(Constants.SESSION_NAME, sessionid.toString());
				return true;
			}
		} else { // 登录操作，则请求doc追加上sessionid
			if (sessionid != null)
				data.addAttribute(Constants.SESSION_NAME, sessionid.toString());
			return true;
		}
	}

	/**
	 * 系统用户登录接口，子类必须实现此方法，并返回验证后的用户对象
	 * 
	 * @param eRequest
	 * @param resData
	 * @param sessio
	 * @return
	 * @throws IllegalArgumentException
	 * @throws SecurityException
	 * @throws IllegalAccessException
	 * @throws InvocationTargetException
	 * @throws NoSuchMethodException
	 * @throws ClassNotFoundException
	 */
	public abstract Object SysOperatorLogin(Element eRequest, Element resData,
			SessionMap sessio) throws IllegalArgumentException,
			SecurityException, IllegalAccessException,
			InvocationTargetException, NoSuchMethodException,
			ClassNotFoundException;

	/**
	 * 调用DAO,根据参数作为属性，将列表bean转换为xml元素
	 * 
	 * @param daoObjcet
	 *            dao对象
	 * 
	 * @param paramMethod
	 *            dao方法名称数组
	 * 
	 * @param paramXML
	 *            输出Bean属性
	 * 
	 * @param eRequest
	 *            请求xml
	 * 
	 * @param resData
	 *            响应xml
	 */
	@SuppressWarnings("unchecked")
	public void callDAOToListBeanJson(Object daoObjcet, String[] paramMethod,
			String[] paramXML, Element eRequest, Element resData)
			throws IllegalArgumentException, SecurityException,
			IllegalAccessException, InvocationTargetException,
			NoSuchMethodException, ClassNotFoundException {
		// call DAO
		Map<String, Object> paramMap = getParamMap(eRequest);
		Object page = paramMap.get("page");
		Object size = paramMap.get("size");
		Object topage = paramMap.get("topage");
		Class<? extends Object> daoClass = daoObjcet.getClass();
		List<ETBase> list;
		if ("".equals(page) || page == null || "".equals(size) || size == null) {// 不分页
			list = (List<ETBase>) daoClass.getDeclaredMethod(paramMethod[0],
					Map.class).invoke(daoObjcet, paramMap);

		} else {
			int ipage = Integer.parseInt(page.toString());// 当前页数
			int isize = Integer.parseInt(size.toString());// 每页记录数
			paramMap.put("startNum", isize * (ipage - 1));

			if (topage == null || "".equals(topage))
				paramMap.put("endNum", isize * ipage);
			else {
				int itopage = Integer.parseInt(topage.toString());// 当前页数
				paramMap.put("endNum", isize * itopage);
			}
			// 总记录数
			long total = (Long) daoClass.getDeclaredMethod(paramMethod[1],
					Map.class).invoke(daoObjcet, paramMap);

			long pages = total / isize;// 总页数
			if (total % isize != 0) {
				pages += 1;
			}
			resData.addAttribute("total", (new Long(total)).toString());
			resData.addAttribute("pages", (new Long(pages)).toString());

			list = (List<ETBase>) daoClass.getDeclaredMethod(paramMethod[0],
					Map.class).invoke(daoObjcet, paramMap);
		}
		// response XML
		if (list != null) {
			//json数组格式输出
//			JSONArray array = JSONArray.fromObject(list.toArray());
			String array=JsonUtil.getJsonStringFromObject(list);
			resData.addCDATA(array.toString());
		}
	}
}
